/**
 * 
 */
package com.netscenery.yang.model;

import java.util.ArrayList;

import org.jdom2.Element;

import com.netscenery.util.Link;
import com.netscenery.util.QName;
import com.netscenery.yang.YangKeyword;
import com.netscenery.yang.YangStatement;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.parser.YangParserException;

/**
 * @author chong
 *
 */
public class Output extends ModelElement {
	private ArrayList<Typedef> typedefs;
	private ArrayList<Grouping> groupings;
	private DataDefEntity dataDefs;
	/**
	 * 
	 */
	public Output() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param env
	 * @param name
	 * @throws ModelException
	 */
	public Output(Env env) throws ModelException {
		if (null == env){
			env = new Env();
		}
		
		this.env = env;
		// TODO Auto-generated constructor stub
	}


	public DataDefEntity getDataDefs() {
		return dataDefs;
	}

	public void setDataDefs(DataDefEntity dataDefs) {
		this.dataDefs = dataDefs;
	}
	public Node createNode(String type,String nodeName) throws ModelException{
		if (null == dataDefs){
			return null;
		}
		return (Node) this.dataDefs.createDataDef(type, nodeName);
	}
	public Uses createUses(String name) throws ModelException{
		if (null == dataDefs){
			return null;
		}
		return (Uses) this.dataDefs.createDataDef(YangKeyword.USES.getKeyword(), name);
	}
	public Uses getUses(String string) {
		if (null == dataDefs){
			return null;
		}
		return dataDefs.getUses(string);
	}


	
	/**
	 * 锟斤拷锟斤拷锟狡达拷锟斤拷一锟斤拷typedef
	 * @param name
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef createTypedef(String name){
		if (null == name){
			return null;
		}
		
		return new Typedef(newSubEnv(),name);
	}
	/**
	 * 锟斤拷锟揭伙拷锟絫ypedef
	 * @param def
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public boolean addTypedef(Typedef def){
		if(null == def){
			return false;
		}
		
		if (null == this.typedefs){
			this.typedefs = new ArrayList<Typedef>(1);
		}
		this.typedefs.add(def);
		Env env = this.getEnv();
		env.addDerivedType(def);
		return true;
	}
	/**
	 * 锟斤拷锟斤拷锟脚伙拷取typedef
	 * @param index
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef getTypedef(int index){
		if (null == this.typedefs){
			return null;
		}
		if (index >= this.typedefs.size()){
			return null;
		}
		return this.typedefs.get(index);
	}
	/**
	 * 锟斤拷锟絫ypedef锟斤拷苹锟饺ypedef
	 * @param defName
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef getTypedef(String defName){
		if (null == this.typedefs){
			return null;
		}
		int size = typedefs.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Typedef def = this.typedefs.get(i);
			if (null != def){
				if (def.getName().equals(defName)){
					return def;
				}
			}
		}
		return null;
	}
	/**
	 * 锟斤拷锟斤拷锟斤拷删锟斤拷typedef
	 * @param index
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef removeTypedef(int index){
		if (null == this.typedefs){
			return null;
		}
		if (index >= this.typedefs.size()){
			return null;
		}
		return this.typedefs.remove(index);
	}
	/**
	 * 锟斤拷锟斤拷锟斤拷删锟斤拷typedef
	 * @param defName
	 * @return
	 */
	public Typedef removeTypedef(String defName){
		if (null == this.typedefs){
			return null;
		}
		int size = typedefs.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Typedef def = this.typedefs.get(i);
			if (null != def){
				if (def.getName().equals(defName)){
					return typedefs.remove(i);
				}
			}
		}
		return null;
	}
	/**
	 * 锟斤拷取typedef锟侥革拷锟斤拷
	 * @return
	 */
	public int getTypedefsNumber(){
		if (null == this.typedefs){
			return 0;
		}
		return this.typedefs.size();
	}


	/**
	 * 锟斤拷取grouping锟斤拷锟斤拷目
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public int getGroupingsNumber(){
		if (null == this.groupings){
			return 0;
		}
		return this.groupings.size();
	}
	/**
	 * 锟斤拷锟街革拷锟斤拷锟斤拷锟狡达拷锟斤拷grouping
	 * @param name
	 * @return
	 * @throws ModelException 
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping createGrouping(String name) throws ModelException{
		if (null == name){
			return null;
		}
		
		return new Grouping(newSubEnv(),name);
	}
	/**
	 * 锟斤拷锟揭伙拷锟絞rouping
	 * @param n
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public boolean addGrouping(Grouping n){
		if(null == n){
			return false;
		}
		
		if (null == this.groupings){
			this.groupings = new ArrayList<Grouping>(1);
		}
		//锟斤拷锟杰和憋拷锟斤拷锟絞rouping锟斤拷锟斤拷
		if (this.getName().equals(n.getName())){
			return false;
		}
		if (null != this.getGrouping(n.getName())){
			return false;
		}
		return this.groupings.add(n);
		

	}
	/**
	 * 锟斤拷锟斤拷锟脚伙拷取Grouping
	 * @param index
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping getGrouping(int index){
		if (null == this.groupings){
			return null;
		}
		if (index >= this.groupings.size()){
			return null;
		}
		return this.groupings.get(index);
	}
	/**
	 * 锟斤拷锟斤拷锟狡伙拷取Grouping
	 * @param name
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping getGrouping(String name){
		if (null == this.groupings){
			return null;
		}
		int size = groupings.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Grouping n = this.groupings.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return n;
				}
			}
		}
		return null;
	}
	/**
	 * 锟斤拷锟斤拷锟斤拷删锟斤拷Grouping
	 * @param index
	 * @return Grouping
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping removeGrouping(int index){
		if (null == this.groupings){
			return null;
		}
		if (index >= this.groupings.size()){
			return null;
		}
		return this.groupings.remove(index);
	}
	/**
	 * 锟斤拷锟斤拷锟斤拷删锟斤拷Grouping
	 * @param name
	 * @return Grouping
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping removeGrouping(String name){
		if (null == this.groupings){
			return null;
		}
		int size = groupings.size();
		if (size <= 0){
			return null;
		}
		
		
		for (int i = 0; i < size; i++){
			Grouping n = this.groupings.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return groupings.remove(i);
				}
			}
		}
		return null;
	}
	
	public ArrayList<Node> getSchemaNodes(){
		int size = getDataDefsNumber();
		if (0 == size){
			return null;
		}
		return dataDefs.getSchemaNodes();
		
	}
	
	public ArrayList<Node> getDataNodes(){
		int size = getDataDefsNumber();
		if (0 == size){
			return null;
		}
		return dataDefs.getDataNodes();
		
	}
	public  boolean addDataDef(DataDefElement n) {
		if (null == dataDefs){
			dataDefs = new DataDefEntity(newSubEnv());
		}
		
		return dataDefs.addDataDef(n);
		
	}
	public DataDefElement getDataDef(int i) {
		if (null == dataDefs){
			return null;
		}
		
		return dataDefs.getDataDef(i);
	}

	public int getDataDefsNumber() {
		if (null == dataDefs){
			return 0;
		}
		return dataDefs.getDataDefsNumber();
	}

	public Node getSon(String nodeName){
		if (null == nodeName){
			return null;
		}
		ArrayList<Node> nodes = getSchemaNodes();
		if (null == nodes){
			return null;
		}
		
		int size = nodes.size();
		
		for (int i = 0; i < size; i++){
			Node n = nodes.get(i);
			if (null == n){
				continue;
			}
			
			if (n.getName().equals(nodeName)){
				return n;
			}
		}
		
		return null;
	}

	

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toYang()
	 */
	@Override
	public YangStatement toYang() {
		YangStatement output = new YangStatement(YangKeyword.OUTPUT.getKeyword());
		
		/*
		 * typedefs
		 */
		if (null != this.typedefs){
			int size = this.getTypedefsNumber();
			for (int i = 0; i < size; i++){
				Typedef def = this.getTypedef(i);
				if (null != def){
					YangStatement defstat = def.writeYang();
					if (null == defstat){
						continue;
					}
					output.addChild(defstat);
				}
			}
		}
		
		/*
		 * groupings
		 */
		if (null != this.groupings){
			int size = this.getGroupingsNumber();
			for (int i = 0; i < size; i++){
				Grouping grp = this.getGrouping(i);
				if (null != grp){
					YangStatement grpstat = grp.writeYang();
					if (null == grpstat){
						continue;
					}
					output.addChild(grpstat);
				}
			}
		}
		
		/*
		 * datadefs
		 */
		if (null != this.dataDefs){
			int size = this.getDataDefsNumber();
			for (int i = 0; i < size; i++){
				DataDefElement n = this.getDataDef(i);
				if (null != n){
					YangStatement nodestat = n.writeYang();
					if (null == nodestat){
						continue;
					}
					output.addChild(nodestat);
				}
			}
		}
		
		return output;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toYin()
	 */
	@Override
	public Element toYin() {
		Element output = new Element(YangKeyword.OUTPUT.getKeyword(),env.getNs());

		
		/*
		 * typedefs
		 */
		if (null != this.typedefs){
			int size = this.getTypedefsNumber();
			for (int i = 0; i < size; i++){
				Typedef def = this.getTypedef(i);
				if (null != def){
					Element defstat = def.writeYin();
					if (null == defstat){
						continue;
					}
					output.addContent(defstat);
				}
			}
		}
		/*
		 * groupings
		 */
		if (null != this.groupings){
			int size = this.getGroupingsNumber();
			for (int i = 0; i < size; i++){
				Grouping grp = this.getGrouping(i);
				if (null != grp){
					Element grpstat = grp.writeYin();
					if (null == grpstat){
						continue;
					}
					output.addContent(grpstat);
				}
			}
		}

		//datadefs
		if (null != this.dataDefs){
			int size = this.getDataDefsNumber();
			for (int i = 0; i < size; i++){
				DataDefElement n = this.getDataDef(i);
				if (null != n){
					Element node = n.writeYin();
					if (null == node){
						continue;
					}
					output.addContent(node);
				}
			}
		}	

		
		return output;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toXML()
	 */
	@Override
	public Element toXML() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readXML(org.jdom2.Element)
	 */
	@Override
	public int readXML(Element element) throws ModelException {
		// TODO Auto-generated method stub
		return 0;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readYin(org.jdom2.Element)
	 */
	@Override
	public int readYin(Element element) throws ModelException {
		if (null == element){
			return MODELELEMENT_OK;
		}
	
		/*
		 * typedefs
		 */
		else if (element.getName().equals(YangStatement.YANG_STATEMENT_TYPEDEF)){

			Env subEnv = newSubEnv();
			Typedef ext = (Typedef) ModelElement.parseYin(subEnv, element);
			this.addTypedef(ext);
		}
		/*
		 * groupings
		 */
		else if (element.getName().equals(YangStatement.YANG_STATEMENT_GROUPING)){

			Env subEnv = newSubEnv();
			Grouping ext = (Grouping) ModelElement.parseYin(subEnv, element);
			this.addGrouping(ext);
		}

		//datadefs
		else if (element.getName().equals(YangStatement.YANG_STATEMENT_CONTAINER)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_CHOICE)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_LEAF)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_LEAFLIST)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_LIST)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_ANYXML)
				|| element.getName().equals(YangStatement.YANG_STATEMENT_USES)){

			Env subEnv = newSubEnv();
			Node n = (Node) ModelElement.parseYin(subEnv, element);
			this.addDataDef(n);
		} 
		else {
			return MODELELEMENT_FAIL;
		}
		return MODELELEMENT_OK;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readYANG(com.netscenery.yang.YangStatement)
	 */
	@Override
	public int readYANG(YangStatement statement) throws YangParserException,
			ModelException {
		if (null == statement){
			return MODELELEMENT_OK;
		}
		String value = statement.getArgument();
		

		/*
		 * typedefs
		 */
		if (statement.getKeyword().equals(YangStatement.YANG_STATEMENT_TYPEDEF)){

			Env subEnv = newSubEnv();
			Typedef ext = (Typedef) ModelElement.parseYANG(subEnv, statement);
			this.addTypedef(ext);
		}
		/*
		 * groupings
		 */
		else if (statement.getKeyword().equals(YangStatement.YANG_STATEMENT_GROUPING)){

			Env subEnv = newSubEnv();
			Grouping ext = (Grouping) ModelElement.parseYANG(subEnv, statement);
			this.addGrouping(ext);
		}

		//datadefs
		else if (statement.getKeyword().equals(YangStatement.YANG_STATEMENT_CONTAINER)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_CHOICE)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_LEAF)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_LEAFLIST)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_LIST)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_ANYXML)
				|| statement.getKeyword().equals(YangStatement.YANG_STATEMENT_USES)
				){
			Env subEnv = newSubEnv();
			DataDefElement n = (DataDefElement) ModelElement.parseYANG(subEnv, statement);
			this.addDataDef(n);
		}   
		else {
			return MODELELEMENT_FAIL;
		}
		
		return MODELELEMENT_OK;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#update()
	 */
	@Override
	public void update() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#isFieldMandatory(java.lang.String)
	 */
	@Override
	public boolean isFieldMandatory(String field) {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#getMapInfo()
	 */
	@Override
	public MapInfo getMapInfo() throws SecurityException, NoSuchMethodException {
		// TODO Auto-generated method stub
		return null;
	}

}
